﻿//-----------------------------------------------------------------------
// <copyright file="O365002 - CheckMethods.cs" company="Kimmo Forss">
// </copyright>
// <summary>The class in this file implements the UseForbiddenMethods class</summary>
// <website>http://O365fxcoprules.codeplex.com/</website>
//-----------------------------------------------------------------------
namespace O365FxCopRules
{
    using System;
    using Microsoft.FxCop.Sdk;

    /// <summary>
    /// This rule checks if the code is using assemblies that are not allowed in Office 365
    /// </summary>
    public class UseForbiddenMethods : BaseIntrospectionRule
    {
        /// <summary>
        /// aa
        /// </summary>
        /// <param name="name"></param>
        public UseForbiddenMethods(string name) :
            base(name, "O365FxCopRules.O365Rules", typeof(UseForbiddenMethods).Assembly)
        {
        }
        /// <summary>
        /// bb
        /// </summary>
        public UseForbiddenMethods() :
            base("UseForbiddenMethods", "O365FxCopRules.O365Rules", typeof(UseForbiddenMethods).Assembly)
        {
        }

        public override TargetVisibilities TargetVisibility
        {
            get
            {
                return TargetVisibilities.All;
            }
        }

        public override void BeforeAnalysis()
        {
            // Do once-per-thread initialization.
        }

        public override void AfterAnalysis()
        {
            // Do once-per-thread cleanup. Rarely needed.
        }
        private bool CheckCalls(Instruction instruction)
        {
            bool forbidden = false;
            bool retValue = false;
            Method call = instruction.Value as Method;
            if (String.Compare(call.FullName, "System.Array.CreateInstance(System.Type,System.Int32)", false) == 0)
            {
                forbidden = true;
            }
            if (call.FullName.StartsWith("System.Type.GetType("))
            {
                forbidden = true;
            }
            if (call.FullName.StartsWith("System.Type.InvokeMember"))
            {
                forbidden = true;
            }

            if (call.FullName.StartsWith("System.Threading.Monitor"))
            {
                bool exception = false;
                if (call.FullName.StartsWith("System.Threading.Monitor.Enter"))
                {
                    exception = true;
                }
                if (call.FullName.StartsWith("System.Threading.Monitor.Exit"))
                {
                    exception = true;
                }
                if (!exception)
                {
                    forbidden = true;
                }
            }

            if (call.FullName.StartsWith("System.Threading.Interlocked"))
            {
                bool exception = false;
                if (call.FullName.StartsWith("System.Threading.Interlocked.CompareExchange"))
                {
                    exception = true;
                }

                if (call.FullName.StartsWith("System.Threading.Thread.get_CurrentThread"))
                {
                    exception = true;
                }

                if (call.FullName.StartsWith("System.Threading.Thread.get_ManagedThreadId"))
                {
                    exception = true;
                }

                if (!exception)
                {
                    forbidden = true;
                }
            }

            if (call.FullName.StartsWith("System.Reflection"))
            {
                bool exception = false;
                if (call.FullName.StartsWith("System.Reflection.FieldInfo.GetFieldFromHandle"))
                {
                    exception = true;
                }

                if (call.FullName.StartsWith("System.Reflection.MethodBase.GetMethodFromHandle"))
                {
                    exception = true;
                }

                if (call.FullName.StartsWith("System.Reflection.FieldInfo.GetValue"))
                {
                    exception = true;
                }

                if (call.FullName.StartsWith("System.Reflection.ConstructorInfo"))
                {
                    exception = true;
                }


                if (call.FullName.StartsWith("System.Reflection.MemberInfo.get_Name"))
                {
                    exception = true;
                }
                if (call.FullName.StartsWith("System.Reflection.MemberInfo.GetCustomAttributes"))
                {
                    exception = true;
                }
                if (call.FullName.StartsWith("System.Reflection.PropertyInfo.get_PropertyType"))
                {
                    exception = true;
                }

                if (call.FullName.StartsWith("System.Reflection.PropertyInfo.GetValue"))
                {
                    exception = true;
                }

                if (call.FullName.StartsWith("System.Reflection.PropertyInfo.SetValue"))
                {
                    exception = true;
                }

                if (call.FullName.StartsWith("System.Reflection.MethodInfo"))
                {
                    exception = true;
                }

                if (!exception)
                {
                    forbidden = true;
                }
            }

            //Added 2011.9.29, DMann
            //Block Finalizers
            if (RuleUtilities.IsFinalizer(call))
            {
                forbidden = true;
            }

            if (forbidden)
            {
                Problem p = new Problem(GetNamedResolution("Forbidden", call.FullName));
                Problems.Add(p);
            }



            return retValue;
        }

        private bool CheckForCreationOfObjects(Instruction instruction)
        {
            bool retValue = false;
            Method ctor = instruction.Value as Method;
            string ctorType = ctor.FullName;
            int i = ctorType.LastIndexOf('#');
            if (i > 0)
            {
                ctorType = ctorType.Substring(0, i - 1);
            }

            if (ctorType.StartsWith("Microsoft.SqlServer"))
            {
                retValue = true;
            }

            if (ctorType.StartsWith("Microsoft.Win32"))
            {
                retValue = true;
            }
            if (ctorType.StartsWith("System.Data.Sql"))
            {
                retValue = true;
            }
            if (ctorType.StartsWith("System.Data.SqlClient"))
            {
                retValue = true;
            }
            if (ctorType.StartsWith("System.Data.SqlTypes"))
            {
                retValue = true;
            }
            if (ctorType.StartsWith("System.IO.Pipes"))
            {
                retValue = true;
            }
            if (ctorType.StartsWith("System.IO.Ports"))
            {
                retValue = true;
            }
            if (ctorType.StartsWith("System.Runtime.Remoting"))
            {
                retValue = true;
            }
            if (ctorType.StartsWith("System.Threading"))
            {
                retValue = true;
            }


            if (ctorType.StartsWith("System.Reflection"))
            {
                retValue = true;
            }

            if (retValue)
            {
                Problems.Add(new Problem(GetResolution(ctorType)));
            }

            return retValue;
        }

        public override ProblemCollection Check(Member member)
        {
            Method method = member as Method;
            if (method != null)
            {
                try
                {
                    foreach (Instruction instruction in method.Instructions)
                    {
                        switch (instruction.OpCode)
                        {
                            case OpCode.Newobj:
                                {
                                    if (CheckForCreationOfObjects(instruction))
                                    {

                                    }
                                    break;


                                }
                            case OpCode.Call:
                            case OpCode.Callvirt:
                                {
                                    if (CheckCalls(instruction))
                                    {

                                    }
                                    break;
                                }

                        }
                    }

                }
                catch (Exception Ex)
                {
                }
            }

            return Problems;

        }

        public override ProblemCollection Check(string namespaceName, TypeNodeCollection types)
        {
            return base.Check(namespaceName, types);
        }

        public override void VisitAssignmentStatement(AssignmentStatement assignment)
        {
            // Process assignment statement. Add to this.Problems if problems are found.

            // Uncomment the following if you need to recurse deeper (for example, to the Expression level).
            base.VisitAssignmentStatement(assignment);
        }

    }
}